package business;

import dao.EmpregadoDAO;
import dao.EmprestimoDAO;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import model.Empregado;
import model.Emprestimo;

public class EmprestimoBO {
    
    private static EmprestimoBO instancia;

    /**
     * Método executado para garantir a existência de apenas uma instância dessa classe (Singleton).
     * 
     * @return uma instância da classe EmpregadoBO 
     * 
     */
    public static EmprestimoBO getInstance() {
        if (instancia == null) {
            instancia = new EmprestimoBO();
        }
        return instancia;
    }

    /**
     * Método executado para validar as informações do empréstimo antes de ser solicitado.
     * 
     * @param Emprestimo a ser solicitado
     * @throws Exception, EmprestimoException
     * 
     */
    public Emprestimo solicitaEmprestimo(Emprestimo emprestimo) throws Exception, EmprestimoException {

        if (EmprestimoBO.getInstance().verificaCpfEmpregado(emprestimo.getEmpregado())) {
            String cpf = emprestimo.getEmpregado().getCpf();
            Empregado empregado = EmpregadoDAO.getInstance().consultaEmpregadoPorCpf(cpf);
            emprestimo.setEmpregado(empregado);
        }

        if (EmprestimoBO.getInstance().verificaCamposObrigatorios(emprestimo)  &&
            EmprestimoBO.getInstance().verificaIdade(emprestimo.getEmpregado())) {

            emprestimo.setLimite(EmprestimoBO.getInstance().obterLimite(emprestimo));
            emprestimo.setTaxaJuros(EmprestimoBO.getInstance().obterTaxaJuros(emprestimo));
            emprestimo.setValorPrestacao(EmprestimoBO.getInstance().obterValorPrestacao(emprestimo));
            emprestimo.setValorTotal(EmprestimoBO.getInstance().obterValorTotal(emprestimo));

        }

        return emprestimo;

    }

    /**
     * Método executado ao confirmar a solicitação de um empréstimo.
     * 
     * @param Emprestimo a ser confirmado
     * @throws Exception, EmprestimoException
     * 
     */
    public void confirmaEmprestimo(Emprestimo emprestimo) throws Exception, EmprestimoException {
        EmprestimoDAO.getInstance().incluir(emprestimo);
    }

    /**
     * Método executado para verificar se os campos obrigatórios estão preenchidos.
     *
     * @param emprestimo do tipo Emprestimo
     * @return Booleano que indica se estão preenchidos ou não
     *
     */
    public boolean verificaCamposObrigatorios(Emprestimo emprestimo) throws EmprestimoException {

        if ((!emprestimo.getEmpregado().getCpf().equals("")) && (emprestimo.getNumPrestacoes() != 0) && (emprestimo.getValorEmprestimo() != null)) {
                return true; 
        }

        throw new EmprestimoException("Os campos obrigatórios não foram preenchidos.");

    }

    /**
     * Método executado para verificar se o CPF entrado corresponde
     * ao CPF de algum empregado previamente cadastrado.
     *
     * @param Empregado
     * @return Booleano que indica se existe esse cpf ou não
     *
     */
    public boolean verificaCpfEmpregado(Empregado empregado) throws EmprestimoException, Exception {

        List<Empregado> listaEmpregados = EmpregadoDAO.getInstance().listar();

        for (int i = 0; i < listaEmpregados.size(); i++) {
                if (empregado.getCpf().equals(listaEmpregados.get(i).getCpf())) {
                        return true;
                }
        }

        throw new EmprestimoException("Não há nenhum empregado cadastrado com esse CPF.");

    }

    /**
     * Método executado para verificar se a idade está dentro do limite
     *
     * @param Empregado
     * @return Booleano que indica se a idade está dentro do limite
     * @throws Exception 
     *
     */
    public boolean verificaIdade(Empregado empregado) throws Exception {

        String dataNascimento = empregado.getDataNascimento();
        int idade = EmpregadoBO.getInstance().calculaIdade(dataNascimento);

        if (empregado.getSexo()) {
            if (idade < 21 || idade > 65) {
                throw new EmprestimoException("Só são concedidos empréstimos para homens entre 21 e 65 anos.");
            }
        }
        else {
            if (idade < 21 || idade > 61) {
                throw new EmprestimoException("Só são concedidos empréstimos para mulheres entre 21 e 61 anos.");
            }
        }

        return true;

    }

    private BigDecimal obterLimite(Emprestimo emprestimo) throws Exception {

        Empregado empregado = emprestimo.getEmpregado();

        String dataNascimento = empregado.getDataNascimento();
        int idade = EmpregadoBO.getInstance().calculaIdade(dataNascimento);

        BigDecimal limite = null;

        if (empregado.getSexo()) {
            limite = EmprestimoBO.getInstance().obterLimiteHomem(idade, emprestimo);
        }
        else {
            limite = EmprestimoBO.getInstance().atribuiLimiteMulher(idade, emprestimo);
        }

        return limite;

    }    

    private BigDecimal obterLimiteHomem(int idade, Emprestimo emprestimo) {

        BigDecimal salario = emprestimo.getEmpregado().getSalario();

        BigDecimal limite = null;

        if (idade >= 21 && idade <= 35) {
            limite = EmprestimoBO.getInstance().obterLimiteHomemEntre21e35Anos(salario);
        } 
        else if (idade >= 36 && idade <= 45) {
            limite = EmprestimoBO.getInstance().obterLimiteHomemEntre36e45Anos(salario);
        }
        else if (idade >= 46 && idade <= 65) {
            limite = EmprestimoBO.getInstance().obterLimiteHomemEntre46e65Anos(salario);
        }

        return limite;

    }

    private BigDecimal obterLimiteHomemEntre21e35Anos(BigDecimal salario) {

        BigDecimal salarioCincoMil = new BigDecimal("5000").setScale(2, RoundingMode.HALF_EVEN);

        if (salario.compareTo(salarioCincoMil) > 0) {
            return salario.multiply(new BigDecimal("0.75"));
        } 
        else {
            return salario.multiply(new BigDecimal("0.70"));
        }

    }

    private BigDecimal obterLimiteHomemEntre36e45Anos(BigDecimal salario) {

        BigDecimal salarioSeisMil  = new BigDecimal("6000").setScale(2, RoundingMode.HALF_EVEN);

        if (salario.compareTo(salarioSeisMil) > 0) {
            return salario.multiply(new BigDecimal("0.60"));
        } 
        else {
            return salario.multiply(new BigDecimal("0.55"));
        }

    }

    private BigDecimal obterLimiteHomemEntre46e65Anos(BigDecimal salario) {
        return salario.multiply(new BigDecimal("0.30"));
    }

    private BigDecimal atribuiLimiteMulher(int idade, Emprestimo emprestimo) {

        BigDecimal salario = emprestimo.getEmpregado().getSalario();

        BigDecimal limite = null;

        if (idade >= 21 && idade <= 30) {
            limite = EmprestimoBO.getInstance().obterLimiteMulherEntre21e30Anos(salario);
        } 
        else if (idade >= 31 && idade <= 44) {
            limite = EmprestimoBO.getInstance().obterLimiteMulherEntre31e44Anos(salario);
        }
        else if (idade >= 45 && idade <= 61) {
            limite = EmprestimoBO.getInstance().obterLimiteMulherEntre45e61Anos(salario);
        }

        return limite;

    }

    private BigDecimal obterLimiteMulherEntre21e30Anos(BigDecimal salario) {
        return salario.multiply(new BigDecimal("0.70"));
    }

    private BigDecimal obterLimiteMulherEntre31e44Anos(BigDecimal salario) {
        return salario.multiply(new BigDecimal("0.50"));
    }

    private BigDecimal obterLimiteMulherEntre45e61Anos(BigDecimal salario) {
        return salario.multiply(new BigDecimal("0.35"));
    }

    private BigDecimal obterTaxaJuros(Emprestimo emprestimo) {

        int numPrestacoes = emprestimo.getNumPrestacoes();

        BigDecimal taxaJuros = null;

        if (numPrestacoes >= 1 && numPrestacoes <= 3) {
            taxaJuros = new BigDecimal("0.05");
        } 
        else if (numPrestacoes >= 4 && numPrestacoes <= 9) {
            taxaJuros = new BigDecimal("0.065");
        }
        else if (numPrestacoes >= 10 && numPrestacoes <= 15) {
            taxaJuros = new BigDecimal("0.08");
        }
        else if (numPrestacoes >= 16 && numPrestacoes <= 24) {
            taxaJuros = new BigDecimal("0.1");
        }

        return taxaJuros;

    }   

    private BigDecimal obterValorPrestacao(Emprestimo emprestimo) {

        BigDecimal i = emprestimo.getTaxaJuros();
        int n = emprestimo.getNumPrestacoes();


        /* CF = i / ( 1 - ( 1 / ((1+i) ^ n)) )
         * 
         * cálculo de dentro pra fora
         * 
         */

        double temp = 1 + i.doubleValue();
        double tempp = Math.pow(temp, n);
        double temppp = 1 / tempp;
        double tempppp = 1 - temppp;

        double cf = i.doubleValue() / tempppp;

        double valorPrestacao = emprestimo.getValorEmprestimo().doubleValue() * cf;

        return new BigDecimal(valorPrestacao).setScale(2, RoundingMode.HALF_EVEN);

    }  

    private BigDecimal obterValorTotal(Emprestimo emprestimo) {

        BigDecimal valorPrestacao = emprestimo.getValorPrestacao();
        BigDecimal numPrestacoes = new BigDecimal(emprestimo.getNumPrestacoes());

        return valorPrestacao.multiply(numPrestacoes);

    }
    
}